package rsvp.util;

import java.util.Date;



/**
 * This class implements a StopWatch behavior. It is useful for speed testing.
 * This watch reports difference in milliseconds.
 * 
 * <p>
 * 
 * @author Kuki Szabolcs @version 2002-04-03, changed to StopWatch 2003-02-26
 */
public class StopWatch
{
    private long m_lCumulatedBeforeStart = 0;
    private Date m_dStartDate            = null;
    private int  m_iStartCount           = 0;
  
    /**
     * also starts the StopWatch
     * 
     * @version 2/26/2003
     */
    public StopWatch()
    {
        start();
    }

    /**
     * also starts the StopWatch if bStartWatch is true
     * 
     * @param bStartWatch
     *            a boolean
     * 
     * @version 2/26/2003
     */
    public StopWatch(boolean bStartWatch)
    {
        if (bStartWatch)
            start();
    }

    /**
     * start/continue the StopWatch
     * 
     * @version 2/26/2003
     */
    public void start()
    {
        m_iStartCount++;
        m_dStartDate = new Date();
    }

    /**
     * stop the watch (does not reset and start will continue)
     * 
     * @return a long
     * 
     * @version 2/26/2003
     */
    public long stop()
    {
        Date now = new Date();
        if (null != m_dStartDate)
        {
            m_lCumulatedBeforeStart += now.getTime() - m_dStartDate.getTime();
            m_dStartDate = null;
        }

        return read();
    }

    /**
     * stop counter and set to the specified ms time
     * 
     * @param l_msTime
     *            time to set to in miliseconds
     * @return a long the value before reset
     * 
     * @version 2/26/2003
     */
    public long setTo(long l_msTime)
    {
        long lTime = stop();

        m_dStartDate = null;
        m_lCumulatedBeforeStart = l_msTime;

        return lTime;
    }

    /**
     * reset counter if the stop watch and does start again the watch
     * 
     * @return a long the value before reset
     * 
     * @version 2/26/2003
     */
    public long reset()
    {
        long lTime = stop();

        m_dStartDate = null;
        m_lCumulatedBeforeStart = 0;
        m_iStartCount = 0;

        start();
        return lTime;
    }

    /**
     * read the current value in ms
     * 
     * @return a long
     * 
     * @version 2/26/2003
     */
    public long read()
    {
        long lTimeCounted = m_lCumulatedBeforeStart;
        if (null != m_dStartDate)
        {
            Date now = new Date();
            lTimeCounted += now.getTime() - m_dStartDate.getTime();
        }

        return lTimeCounted;
    }

    /**
     * returns number of starts given since last reset (or since the object was
     * constructed)
     * 
     * @return an integer
     * 
     * @version 3/7/2003
     */
    public int getStartNoResetCount()
    {
        return m_iStartCount;
    }

    /**
     * @return read StopWatch value in days/hours/minutes/seconds/milliseconds
     *         format
     */
    public String readFormated()
    {
        return formatMsToHR(read());
    }
    
    /**
     * format a long (miliseconds) in days/hours/minutes/seconds/milisecconds
     * 
     * @param lMilisecconds
     *            the miliseconds which should be transformed in
     *            days/hours/minutes/seconds/milisecconds
     * @return a human readable string (3d 14h 34m 44s 843ms)
     * 
     * @author Kuki Szabolcs
     * @version (time) Jan 21, 2004 9:30:01 AM
     */
    public static String formatMsToHR(long lMilisecconds)
    {    	
        String sbRet = "";
        if (lMilisecconds >= DateUtilities.F_millisecOfADay)
        {
            sbRet += "" + lMilisecconds / DateUtilities.F_millisecOfADay + "d ";
            lMilisecconds -= (lMilisecconds / DateUtilities.F_millisecOfADay)
                             * DateUtilities.F_millisecOfADay;
        }

        if (lMilisecconds >= DateUtilities.F_millisecOfAnHour)
        {
            sbRet += "" + lMilisecconds / DateUtilities.F_millisecOfAnHour
                     + "h ";
            lMilisecconds -= (lMilisecconds / DateUtilities.F_millisecOfAnHour)
                             * DateUtilities.F_millisecOfAnHour;
        }

        if (lMilisecconds >= DateUtilities.F_millisecOfAMinute)
        {
            sbRet += "" + lMilisecconds / DateUtilities.F_millisecOfAMinute
                     + "m ";
            lMilisecconds -= (lMilisecconds / DateUtilities.F_millisecOfAMinute)
                             * DateUtilities.F_millisecOfAMinute;
        }

        if (lMilisecconds >= DateUtilities.F_millisecOfASeccond)
        {
            sbRet += "" + lMilisecconds / DateUtilities.F_millisecOfASeccond
                     + "s ";
            lMilisecconds -= (lMilisecconds / DateUtilities.F_millisecOfASeccond)
                             * DateUtilities.F_millisecOfASeccond;
        }
        
        if (lMilisecconds != 0 || (sbRet.length() ==0))
			sbRet += "" + lMilisecconds + "ms";
        
        return sbRet.trim();
    }

    /**
     * 
     * @return time stamp on when the stop watch was started
     */
    public Date getStartDate() 
    {
    	return this.m_dStartDate;
    }
}
